package org.framework.lazy.cloud.network.heartbeat.protocol.socket5;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.socksx.v5.*;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

@Slf4j
public class Socks5CommandRequestHandler extends SimpleChannelInboundHandler<Socks5CommandRequest> {
    private final EventLoopGroup group;

    public Socks5CommandRequestHandler(EventLoopGroup group) {
        this.group = group;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Socks5CommandRequest request) throws Exception {
        if (request.type() == Socks5CommandType.CONNECT) {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new Dest2ClientInboundHandler(ctx));
                        }
                    });
            log.info("准备连接目标服务器，ip={},port={}", request.dstAddr(), request.dstPort());
            ChannelFuture f = b.connect(new InetSocketAddress(request.dstAddr(), request.dstPort()));
            f.addListener((ChannelFutureListener) future -> {

                if (future.isSuccess()) {
                    log.info("目标服务器连接成功");
                    //添加客户端转发请求到服务端的Handler
                    ctx.pipeline().addLast(new Client2DestInboundHandler(future));
                    DefaultSocks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.SUCCESS, request.dstAddrType());
                    ctx.writeAndFlush(commandResponse);
                    ctx.pipeline().remove(Socks5CommandRequestHandler.class);
                    ctx.pipeline().remove(Socks5CommandRequestDecoder.class);
                } else {
                    log.error("连接目标服务器失败,address={},port={}", request.dstAddr(), request.dstPort());
                    DefaultSocks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.FAILURE, request.dstAddrType());
                    ctx.writeAndFlush(commandResponse);
                    future.channel().close();
                }

            });
        } else {
            log.info("receive commandRequest type={}", request.type());
            ReferenceCountUtil.retain(request);
            ctx.fireChannelRead(request);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}    